#include <AppException.h>
#include "StateEngine.h"
#include "scImpl.h"

#define FCT "StateEngine::StateEngine"
StateEngine::StateEngine() :
	numStates(0), numTransi(0), state(-1)
{

}

#undef FCT
#define FCT "StateEngine::~StateEngine"
StateEngine::~StateEngine()
{

}

#undef FCT
#define FCT "StateEngine::addState"
int StateEngine::addState(std::string stateName)
{
	states.insert(States::value_type(numStates, stateName));
	if(!numStates)
		state=0;
	++numStates;
	return numStates-1;
}

#undef FCT
#define FCT "StateEngine::addTransition"
int StateEngine::addTransition(int sourceState, int targetState)
{
	transis.insert(Transis::value_type(sourceState, pair<int,int>(targetState, numTransi)));
	++numTransi;
	return numTransi-1;
}

#undef FCT
#define FCT "StateEngine::toString"
std::string StateEngine::toString() const
{
	ostringstream os;
	for(States::const_iterator it(states.begin()); it!=states.end(); ++it)
	{
		if(state==it->first)
			os <<">>";
		os <<it->first<<": "<<it->second<<endl;
	}
	for(Transis::const_iterator it(transis.begin()); it!=transis.end(); ++it)
		os <<it->second.second<<": "<<it->first<<" -> "<<it->second.first<<endl;
	return os.str();
}

#undef FCT
#define FCT "StateEngine::makeTransition"
int StateEngine::makeTransition(int targetState)
{
	int res(tryTransition(targetState));
	if(res>=0)
		return res;
	ostringstream os;
	os <<FCT<<": no transition "<<state<<" -> "<<targetState<<" available"<<endl;
	throw new AppException(os.str().c_str(), true);
}

#undef FCT
#define FCT "StateEngine::tryTransition"
int StateEngine::tryTransition(int targetState)
{
	int oldState(state);
	int res(-1);
	pair<Transis::iterator, Transis::iterator> opt(transis.equal_range(state));
	for(Transis::iterator it(opt.first); it!=opt.second; ++it)
		if(it->second.first==targetState)
		{
			state=targetState;
			res=it->second.second;
		}
	if(oldState!=state)
		emit stateChangeSig(state);
	else if(res>=0)
		emit stateRenewSig(state);
	return res;
}

#undef FCT
#define FCT "StateEngine::testTransition"
int StateEngine::testTransition(int targetState) const
{
	pair<Transis::const_iterator, Transis::const_iterator> opt(transis.equal_range(state));
	for(Transis::const_iterator it(opt.first); it!=opt.second; ++it)
		if(it->second.first==targetState)
			return it->second.second;
	return -1;
}

ostream& std::operator<<(ostream& out, const sybilpm::StateEngine & data)
{
	out <<data.toString().c_str();
	return out;
}
